
import ipmsg_protocol  as pt 
import os 

file_attrs_v2s = {\
pt.IPMSG_FILE_UID:'uid',
pt.IPMSG_FILE_USERNAME:'username',
pt.IPMSG_FILE_GID:'gid',
pt.IPMSG_FILE_GROUPNAME:'groupname',
pt.IPMSG_FILE_CLIPBOARDPOS:'clipboardpos',
pt.IPMSG_FILE_PERM:'perm',
pt.IPMSG_FILE_MAJORNO:'majorno',
pt.IPMSG_FILE_MINORNO:'minorno',
pt.IPMSG_FILE_CTIME:'ctime',
pt.IPMSG_FILE_MTIME:'mtime',
pt.IPMSG_FILE_ATIME:'atime',
pt.IPMSG_FILE_CREATETIME:'createtime',
pt.IPMSG_FILE_CREATOR:'creator',
pt.IPMSG_FILE_FILETYPE:'filetype',
pt.IPMSG_FILE_FINDERINFO:'finderinfo',
pt.IPMSG_FILE_ACL:'acl',
pt.IPMSG_FILE_ALIASFNAME:'aliasfname'}

file_attrs_s2v = { \
'uid':pt.IPMSG_FILE_UID,
'username':pt.IPMSG_FILE_USERNAME,
'gid':pt.IPMSG_FILE_GID,
'groupname':pt.IPMSG_FILE_GROUPNAME,
'clipboardpos':pt.IPMSG_FILE_CLIPBOARDPOS,
'perm':pt.IPMSG_FILE_PERM,
'majorno':pt.IPMSG_FILE_MAJORNO,
'minorno':pt.IPMSG_FILE_MINORNO,
'ctime':pt.IPMSG_FILE_CTIME,
'mtime':pt.IPMSG_FILE_MTIME,
'atime':pt.IPMSG_FILE_ATIME,
'createtime':pt.IPMSG_FILE_CREATETIME,
'creator':pt.IPMSG_FILE_CREATOR,
'filetype':pt.IPMSG_FILE_FILETYPE,
'finderinfo':pt.IPMSG_FILE_FINDERINFO,
'acl':pt.IPMSG_FILE_ACL,
'aliasfname':pt.IPMSG_FILE_ALIASFNAME}

def file_data_depack(data):
    dl = len(data)
    bt = bytearray(data[:min(dl,100)]).find(b':')
    if bt < 0: 
        if dl > 100: return None # 数据分析错误 
        else: return {} # 可能是数据太少，所以查找不足

    size = data[:bt]
    head_data = data[:int(size.decode('gbk'),base=16)].decode('gbk') 
    print(head_data)
    file_attr = [['i16','hsize'],['s','fname'],['s','fsize'],['i16','fattr']]
    hs = head_data.split(':')
    file_info = {}
    for fa_i, fa in enumerate(file_attr):
        t = hs[fa_i] 
        if fa[0] == 'i16':
            file_info[fa[1]] = int(t,base=16)
        elif fa[0] == 'i':
            file_info[fa[1]] = int(t)
        elif fa[0] == 's':
            file_info[fa[1]] = t
        else:
            print('error type:%s'%(fa[0]))

    # fsize 段， 如果是目录，这个段是10进制的， 其他的文件类型，是16进制，所以分开处理
    if file_info['fattr'] == pt.IPMSG_FILE_DIR:
        try:
            file_info['fsize'] = int(file_info['fsize'])
        except:
            print('try decode 16')
            file_info['fsize'] = int(file_info['fsize'],base=16)
    else:
        file_info['fsize'] = int(file_info['fsize'],base=16)

    # 其他数据段，如果分析错误，不影响整个文件的运行
    try:
        for h in hs[fa_i+1:]:
            d = h.split('=')
            if len(d) < 2: continue
            attr = int(d[0],base=16)
            if attr in file_attrs_v2s:
                file_info[d[0]] = d[1]
    except Exception as e:
        print('ext error:',e)
    return file_info
    

if __name__ == '__main__':
    f = 'data.dat'
    fr = open(f,'rb') 
    data = fr.read()
    dx = {'dir':[], 'dir_size':[], 'dir_off':[], 'file':'', 'file_size':0, 'file_off':0, 'last_data':b''} #
    data_off = 0
    while len(data) > data_off:
        finfo = file_data_depack(data[data_off:])
        print(finfo)
        if finfo['fattr']== pt.IPMSG_FILE_DIR:
            dx['dir'].append(finfo['fname'])
            dx['dir_size'].append(finfo['fsize'])
            dx['dir_off'].append([])
            dir_path = '/'.join(dx['dir'])
            if not os.path.exists(dir_path):
                os.makedirs(dir_path)
            data_off += finfo['hsize']
        elif finfo['fattr']== pt.IPMSG_FILE_RETPARENT:
            dx['dir'].pop(-1)
            dx['dir_size'].pop(-1)
            data_off += finfo['hsize'] 
            dx['dir_off'].pop(-1)
        else:
            data_off += finfo['hsize'] 
            dx['file'] = finfo['fname']
            fpath = os.path.join('/'.join(dx['dir']), dx['file'])
            with open(fpath, 'wb') as fw:
                fw.write(data[data_off:data_off+finfo['fsize']])
            data_off += finfo['fsize']
            dx['dir_off'][-1].append(finfo['fsize'])
            if sum(dx['dir_off'][-1]) == dx['dir_size']:
                dx['dir'].pop(-1)
                dx['dir_size'].pop(-1)
                dx['dir_off'].pop(-1)